#ifndef __KERN_MM_SWAP_H__
#define __KERN_MM_SWAP_H__

#include <types.h>
#include <memlayout.h>
#include <vmm.h>
#include <list.h>

/* *
 * swap_entry_t
 * --------------------------------------------
 * |         offset        |   reserved   | 0 |
 * --------------------------------------------
 *           24 bits            7 bits    1 bit
 * */

#define MAX_SWAP_OFFSET_LIMIT                   (1 << 24)

#define SWAP_UNUSED                     0xFFFF
#define MAX_SWAP_REF                    0xFFFE

extern size_t max_swap_offset;
extern unsigned short *mem_map;

typedef struct {
    list_entry_t swap_list;
    size_t nr_pages;
} swap_list_t;

extern swap_list_t active_list;
extern swap_list_t inactive_list;

#define nr_active_pages                 (active_list.nr_pages)
#define nr_inactive_pages               (inactive_list.nr_pages)

/* *
 * swap_offset - takes a swap_entry (saved in pte), and returns
 * the corresponding offset in swap mem_map.
 * */
#define swap_offset(entry) ({                                       \
            size_t __offset = (entry >> 8);                         \
            if (!(__offset > 0 && __offset < max_swap_offset)) {    \
                panic("invalid swap_entry_t = %08x.\n", entry);     \
            }                                                       \
            __offset;                                               \
        })

void swap_init(void);
bool try_free_pages(size_t n);

void swap_remove_entry(swap_entry_t entry);
int swap_page_count(struct Page *page);
void swap_duplicate(swap_entry_t entry);
int swap_in_page(swap_entry_t entry, struct Page **pagep);
int swap_copy_entry(swap_entry_t entry, swap_entry_t *store);

int kswapd_main(void *arg) __attribute__((noreturn));

void check_mm_swap(void);
void check_mm_shm_swap(void);

int swap_out_mm(struct mm_struct *mm, size_t require);
void refill_inactive_scan(void);
int page_launder(void);

#endif /* !__KERN_MM_SWAP_H__ */

